/** Copyright [handsomezhou] T9 search library,for T9 pinyin search.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
package com.yunfeng.supercall.contactsutils;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.provider.ContactsContract;
import android.util.Log;

import com.t9search.model.PinyinUnit;
import com.t9search.util.T9MatchPinyinUnits;
import com.yunfeng.supercall.bean.ContactsBaseBean;
import com.yunfeng.supercall.bean.ContactsBaseBean.SearchByType;
import com.yunfeng.supercall.bean.SuperFriendsBean;

/**
 * T9 搜索实现
 * 
 * @author handsomezhou
 * 
 * @see https://github.com/handsomezhou/T9SearchLibrary
 */
public class ContactsHelper {
	private static final String TAG = "ContactsHelper";
	private Context mContext;
	private static ContactsHelper mInstance = null;
	private List<SuperFriendsBean> mBaseContacts = null; // The basic data used for
														// the search
	private List<SuperFriendsBean> mSearchContacts = null; // The search results
														// from the basic data
	/*
	 * save the first input string which search no result.
	 * mFirstNoSearchResultInput.size<=0, means that the first input string
	 * which search no result not appear. mFirstNoSearchResultInput.size>0,
	 * means that the first input string which search no result has appeared,
	 * it's mFirstNoSearchResultInput.toString(). We can reduce the number of
	 * search basic data by the first input string which search no result.
	 */
	private StringBuffer mFirstNoSearchResultInput = null;
	private OnContactsLoad mOnContactsLoad = null;
	private OnContactsChanged mOnContactsChanged = null;
	private ContentObserver mContentObserver;
	private boolean mContactsChanged = true;
	private Handler mContactsHandler = new Handler();

	public interface OnContactsLoad {
		void onContactsLoadSuccess();

		void onContactsLoadFailed();
	}

	public interface OnContactsChanged {
		void onContactsChanged();
	}

	private ContactsHelper(Context context) {
		initContactsHelper(context);
		// registerContentObserver();
	}

	public static ContactsHelper getInstance(Context context) {
		if (null == mInstance) {
			mInstance = new ContactsHelper(context);
		}

		return mInstance;
	}

	public void destroy() {
		if (null != mInstance) {
			// unregisterContentObserver();
			mInstance = null;// the system will free other memory.
		}
	}

	public List<SuperFriendsBean> getBaseContacts() {
		return mBaseContacts;
	}

	public void setBaseContacts(List<SuperFriendsBean> baseContacts) {
		mBaseContacts = baseContacts;
	}

	public List<SuperFriendsBean> getSearchContacts() {
		return mSearchContacts;
	}

	// public void setSearchContacts(List<Contacts> searchContacts) {
	// mSearchContacts = searchContacts;
	// }

	public OnContactsLoad getOnContactsLoad() {
		return mOnContactsLoad;
	}

	public void setOnContactsLoad(OnContactsLoad onContactsLoad) {
		mOnContactsLoad = onContactsLoad;
	}

	private boolean isContactsChanged() {
		return mContactsChanged;
	}

	private void setContactsChanged(boolean contactsChanged) {
		mContactsChanged = contactsChanged;
	}

	/**
	 * @description search base data according to string parameter
	 * @param search
	 *            (valid characters include:'0'~'9','*','#')
	 * @return void
	 * 
	 * 
	 */
	public void parseT9InputSearchContacts(String search) {
		if (null == search) {// add all base data to search
			if (null != mSearchContacts) {
				mSearchContacts.clear();
			} else {
				mSearchContacts = new ArrayList<SuperFriendsBean>();
			}

			for (ContactsBaseBean contacts : mBaseContacts) {
				contacts.setSearchByType(SearchByType.SearchByNull);
				contacts.clearMatchKeywords();
			}

			mSearchContacts.addAll(mBaseContacts);
			mFirstNoSearchResultInput.delete(0,
					mFirstNoSearchResultInput.length());
			Log.i(TAG, "null==search,mFirstNoSearchResultInput.length()="
					+ mFirstNoSearchResultInput.length());
			return;
		}

		if (mFirstNoSearchResultInput.length() > 0) {
			if (search.contains(mFirstNoSearchResultInput.toString())) {
				Log.i(TAG,
						"no need  to search,null!=search,mFirstNoSearchResultInput.length()="
								+ mFirstNoSearchResultInput.length() + "["
								+ mFirstNoSearchResultInput.toString() + "]"
								+ ";searchlen=" + search.length() + "["
								+ search + "]");
				return;
			} else {
				Log.i(TAG,
						"delete  mFirstNoSearchResultInput, null!=search,mFirstNoSearchResultInput.length()="
								+ mFirstNoSearchResultInput.length()
								+ "["
								+ mFirstNoSearchResultInput.toString()
								+ "]"
								+ ";searchlen="
								+ search.length()
								+ "["
								+ search + "]");
				mFirstNoSearchResultInput.delete(0,
						mFirstNoSearchResultInput.length());
			}
		}

		if (null != mSearchContacts) {
			mSearchContacts.clear();
		} else {
			mSearchContacts = new ArrayList<SuperFriendsBean>();
		}

		int contactsCount = mBaseContacts.size();

		/**
		 * search process: 1:Search by name (1)Search by name pinyin
		 * characters(org name->name pinyin characters) ('0'~'9','*','#')
		 * (2)Search by org name ('0'~'9','*','#') 2:Search by phone number
		 * ('0'~'9','*','#')
		 */
		for (int i = 0; i < contactsCount; i++) {

			List<PinyinUnit> pinyinUnits = mBaseContacts.get(i)
					.getNamePinyinUnits();
			StringBuffer chineseKeyWord = new StringBuffer();// In order to get
																// Chinese
																// KeyWords.Of
																// course it's
																// maybe not
																// Chinese
																// characters.
			String name = mBaseContacts.get(i).getNick_name();
			if (true == T9MatchPinyinUnits.matchPinyinUnits(pinyinUnits, name,
					search, chineseKeyWord)) {// search by NamePinyinUnits;
				mBaseContacts.get(i).setSearchByType(SearchByType.SearchByName);
				mBaseContacts.get(i)
						.setMatchKeywords(chineseKeyWord.toString());
				chineseKeyWord.delete(0, chineseKeyWord.length());
				mSearchContacts.add(mBaseContacts.get(i));
				continue;
			} else {
				if (mBaseContacts.get(i).matches(search)) { // search
															// by
															// phone
															// number
					mBaseContacts.get(i).setSearchByType(
							SearchByType.SearchByPhoneNumber);
					mBaseContacts.get(i).setMatchKeywords(search);
					mSearchContacts.add(mBaseContacts.get(i));
					continue;
				}

			}
		}

		if (mSearchContacts.size() <= 0) {
			if (mFirstNoSearchResultInput.length() <= 0) {
				mFirstNoSearchResultInput.append(search);
				Log.i(TAG,
						"no search result,null!=search,mFirstNoSearchResultInput.length()="
								+ mFirstNoSearchResultInput.length() + "["
								+ mFirstNoSearchResultInput.toString() + "]"
								+ ";searchlen=" + search.length() + "["
								+ search + "]");
			} else {

			}
		}

	}

	private void initContactsHelper(Context context) {
		mContext = context;
		setContactsChanged(true);
		if (null == mBaseContacts) {
			mBaseContacts = new ArrayList<SuperFriendsBean>();
		} else {
			mBaseContacts.clear();
		}

		if (null == mSearchContacts) {
			mSearchContacts = new ArrayList<SuperFriendsBean>();
		} else {
			mSearchContacts.clear();
		}

		if (null == mFirstNoSearchResultInput) {
			mFirstNoSearchResultInput = new StringBuffer();
		} else {
			mFirstNoSearchResultInput.delete(0,
					mFirstNoSearchResultInput.length());
		}
	}

	private void registerContentObserver() {
		if (null == mContentObserver) {
			mContentObserver = new ContentObserver(mContactsHandler) {

				@Override
				public void onChange(boolean selfChange) {
					// TODO Auto-generated method stub
					setContactsChanged(true);
					if (null != mOnContactsChanged) {
						Log.i("ActivityTest",
								"mOnContactsChanged mContactsChanged="
										+ mContactsChanged);
						mOnContactsChanged.onContactsChanged();
					}
					super.onChange(selfChange);
				}

			};
		}

		if (null != mContext) {
			mContext.getContentResolver().registerContentObserver(
					ContactsContract.CommonDataKinds.Phone.CONTENT_URI, true,
					mContentObserver);
		}
	}

	private void unregisterContentObserver() {
		if (null != mContentObserver) {
			if (null != mContext) {
				mContext.getContentResolver().unregisterContentObserver(
						mContentObserver);
			}
		}
	}

	private void parseContacts(List<SuperFriendsBean> contacts) {
		if (null == contacts || contacts.size() < 1) {
			if (null != mOnContactsLoad) {
				mOnContactsLoad.onContactsLoadFailed();
			}
			return;
		}

		for (SuperFriendsBean contact : contacts) {
			if (!mBaseContacts.contains(contact)) {
				mBaseContacts.add(contact);
			}
		}

		if (null != mOnContactsLoad) {
			parseT9InputSearchContacts(null);
			mOnContactsLoad.onContactsLoadSuccess();
		}

		return;
	}

}
